﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Net;

namespace Faster.GameUtility
{
    public class AMFPostData
    {
        public List<byte> Message;

        /// <summary>      
        /// 初始化Message      
        /// </summary>      
        /// <param name="amftype"></param>      
        /// <param name="headers"></param>      
        /// <param name="bodies"></param>      
        public AMFPostData(AMFType amftype, int headers, int bodies)
        {
            //AMF版本      
            if (amftype == AMFType.AMF0)
            {
                Message = new List<byte>(new byte[] { 0x00, 0x00 });
            }
            else if (amftype == AMFType.AMF3)
            {
                Message = new List<byte>(new byte[] { 0x00, 0x03 });
            }

            //header数量      
            Message.Add(BitConverter.GetBytes(headers)[1]);
            Message.Add(BitConverter.GetBytes(headers)[0]);
            //body数量      
            Message.Add(BitConverter.GetBytes(bodies)[1]);
            Message.Add(BitConverter.GetBytes(bodies)[0]);
        }

        #region 获取百度指数方法
        /// <summary>
        /// 获取百度指数
        /// </summary>
        /// <param name="keyword">关键词</param>
        /// <param name="start">开始时间</param>
        /// <param name="end">结束时间</param>
        /// <returns></returns>
        public static List<int> GetBaiduIndex(string keyword, string start, string end)
        {
            byte[] data = GetData(keyword, start, end);
            string gateway = "http://index.baidu.com/gateway.php";
            byte[] responseData = GetFlashData(gateway, data);
            if (responseData == null)
            {
                return null;
            }
            List<int> result = GetIndexs(responseData);
            return result;
        }
        #endregion
        /// <summary>      
        /// 添加Target      
        /// </summary>      
        /// <param name="target"></param>      
        /// <param name="response"></param>      
        public void AddTargetAndResponse(string target, string response)
        {
            //添加Target长度      
            Message.Add(BitConverter.GetBytes(target.Length)[1]);
            Message.Add(BitConverter.GetBytes(target.Length)[0]);
            //添加Target内容      
            Message.AddRange(Encoding.UTF8.GetBytes(target));

            //添加Response长度      
            Message.Add(BitConverter.GetBytes(response.Length)[1]);
            Message.Add(BitConverter.GetBytes(response.Length)[0]);
            //添加Response内容      
            Message.AddRange(Encoding.UTF8.GetBytes(response));
        }

        /// <summary>      
        /// 添加Body      
        /// </summary>      
        /// <param name="length"></param>      
        /// <param name="Content"></param>      
        public void AddBody(AMFPostDataBody amfpostdatabody)
        {
            Message.AddRange(amfpostdatabody.GetLength());
            Message.AddRange(amfpostdatabody.Content.ToArray());
        }

        private static byte[] GetData(string key, string startdate, string enddate)
        {
            AMFPostData amfpostdata = new AMFPostData(AMFType.AMF3, 0, 1);
            amfpostdata.AddTargetAndResponse("DataAccessor.getIndexes", "/1");

            AMFPostDataBody amfpostdatabody = new AMFPostDataBody(DataType.Array, 3);
            amfpostdatabody.AddData(DataType.String, key);
            amfpostdatabody.AddData(DataType.String, "0");
            amfpostdatabody.AddData(DataType.String, startdate + "|" + enddate);

            amfpostdata.AddBody(amfpostdatabody);

            byte[] data = amfpostdata.Message.ToArray();

            return data;
        }

        public static byte[] GetFlashData(string gateway, byte[] data)
        {
            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(gateway);
            request.Method = "Post";
            request.ContentType = "application/x-amf";
            CookieContainer cookie = new CookieContainer();
            request.CookieContainer = cookie;
            byte[] requestData = data;
            request.ContentLength = requestData.Length;
            byte[] responseData = null;
            try
            {
                using (Stream requestStream = request.GetRequestStream())
                {
                    requestStream.Write(requestData, 0, requestData.Length);
                }

                HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                using (Stream responseStream = response.GetResponseStream())
                {
                    //StreamToBytes是将流转换为二进制字节数组的方法   
                    responseData = StreamToBytes(responseStream);
                }
            }
            catch (Exception ex)
            {
                //SqlHelper.WriteErroLog("IndexBaidu_" + DateTime.Now.ToString(), ex.Message);//错误日志
            }
            return responseData;
        }

        /// <summary>    
        /// 将 Stream 转成 byte[]    
        /// </summary>    
        public static byte[] StreamToBytes(Stream stream)
        {
            List<byte> bytes = new List<byte>();
            byte b = (byte)stream.ReadByte();
            byte b1 = 0, b2 = 0, b3 = 0;
            while (true)
            {
                if (b1 == 0 && b2 == 0 && b3 == 9)
                {
                    break;
                }
                b1 = b2;
                b2 = b3;
                b3 = b;
                bytes.Add(b3);
                b = (byte)stream.ReadByte();
            }

            return bytes.ToArray();
        }
        #region 获取最近20天的百度指数
        /// <summary>
        /// 返回最后20天的百度指数
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        private static List<int> GetIndexs(byte[] data)
        {
            if (data == null)
            {
                return null;
            }
            List<int> result = new List<int>();
            string str = Encoding.UTF8.GetString(data);
            string start = "userIndexes";
            string end = "mediaIndexes";
            int startIndex = str.IndexOf(start) + start.Length;
            int endIndex = str.IndexOf(end);
            string[] temp = str.Substring(startIndex, endIndex - startIndex).Split(',');
            result.Add(StringToInt(temp[temp.Length - 1]));
            int number = 0;
            for (int index = temp.Length - 2; index > temp.Length - 21; index--)
            {
                int.TryParse(temp[index], out number);
                result.Add(number);
            }
            return result;
        }
        //最后一天的数据由于和mediaIndexes中有包含数据类型长度的字节，特殊处理下
        public static int StringToInt(string str)
        {
            int result = 0;
            int number = 0;
            for (int i = 0; i < str.Length; i++)
            {
                number = str[i] - '0';
                if (number >= 0 && number <= 9)
                {
                    result = result * 10 + number;
                }
                else
                {
                    break;
                }
            }
            return result;
        }
        #endregion
    }


    public class AMFPostDataBody
    {
        private byte[] length = new byte[4];
        public List<byte> Content = new List<byte>();

        /// <summary>      
        /// 初始化Body      
        /// </summary>      
        /// <param name="datatype"></param>      
        /// <param name="arraylength"></param>      
        public AMFPostDataBody(DataType datatype, int arraylength)
        {
            //添加类型标识      
            Content.Add((byte)datatype);

            //数组的话添加长度      
            if (datatype == DataType.Array)
            {
                Content.Add(BitConverter.GetBytes(arraylength)[3]);
                Content.Add(BitConverter.GetBytes(arraylength)[2]);
                Content.Add(BitConverter.GetBytes(arraylength)[1]);
                Content.Add(BitConverter.GetBytes(arraylength)[0]);
            }
        }

        public void AddData(DataType datatype, string value)
        {
            //添加类型标识      
            Content.Add((byte)datatype);

            switch (datatype)
            {
                case DataType.Number:
                    AddData(double.Parse(value));
                    break;
                case DataType.String:
                    AddData(value);
                    break;
                case DataType.Boolean:
                    AddData(Boolean.Parse(value));
                    break;
            }
        }


        #region 各种类型处理方法
        /// <summary>      
        /// Boolean      
        /// </summary>      
        /// <param name="flag"></param>      
        private void AddData(bool flag)
        {
            if (flag)
                Content.Add(0x01);
            else
                Content.Add(0x00);
        }
        /// <summary>      
        /// String      
        /// </summary>      
        /// <param name="value"></param>      
        private void AddData(string value)
        {
            //添加长度      
            Content.Add(BitConverter.GetBytes(Encoding.UTF8.GetBytes(value).Length)[1]);
            Content.Add(BitConverter.GetBytes(Encoding.UTF8.GetBytes(value).Length)[0]);
            //添加内容      
            Content.AddRange(Encoding.UTF8.GetBytes(value));
        }
        /// <summary>      
        /// Number      
        /// </summary>      
        /// <param name="number"></param>      
        private void AddData(double number)
        {
            byte[] b = new byte[8];
            b = BitConverter.GetBytes(number);
            for (int i = 7; i > -1; i--)
            {
                Content.Add(b[i]);
            }
        }
        #endregion

        public byte[] GetLength()
        {
            length[0] = BitConverter.GetBytes(Content.Count)[3];
            length[1] = BitConverter.GetBytes(Content.Count)[2];
            length[2] = BitConverter.GetBytes(Content.Count)[1];
            length[3] = BitConverter.GetBytes(Content.Count)[0];

            return length;
        }
    }


    #region 枚举
    public enum AMFType
    {
        AMF0,
        AMF3
    }

    public enum DataType
    {
        Number = 0,
        Boolean = 1,
        String = 2,
        UntypedObject = 3,
        MovieClip = 4,
        Null = 5,
        Undefined = 6,
        ReferencedObject = 7,
        MixedArray = 8,
        End = 9,
        Array = 10,//0x0A      
        Date = 11,//0x0B      
        LongString = 12,//0x0C      
        TypeAsObject = 13,//0x0D      
        Recordset = 14,//0x0E      
        Xml = 15,//0x0F      
        TypedObject = 16,//0x10      
        AMF3data = 17//0x11      
    }
    #endregion
}
